﻿/********************************************************************************
 * This code is provided as-is, with no explicit or implicit guaranties         *
 * and is governed by the Common Creative License.                              *
 *                                                                              *
 * If you find this code useful and decide to use it for your                   *
 * own proyects, please be sure to copy this complete header, along             *
 * with the authors name.                                                       *
 *                                                                              *
 * A link back from your personal site to the articles URL                      *
 * will also be appreciated                                                     *
 *                                                                              *
 * @author: Matthias Reichenbach                                                *
 * (http://www.codeproject.com/script/Membership/Profiles.aspx?mid=3576642)     *
 *                                                                              *
 * ******************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FuzzyLogic
{
    public partial class Form1 : Form
    {
        TagakiSugenoFuzzySystem system = new TagakiSugenoFuzzySystem();
        Variable distancia = new Variable();
        Variable angulo = new Variable();


        PointF posPelota = new Point();

        Player[] robots = new Player[10];

        public Form1()
        {
            InitializeComponent();

            distancia.addValue(new VariableValue("left", new TriangleMembershipFunction(-4000, -10, 0)));
            distancia.addValue(new VariableValue("center", new TriangleMembershipFunction(-10, 0, 10)));
            distancia.addValue(new VariableValue("right", new TriangleMembershipFunction(0, 10, 4000)));

            angulo.addValue(new VariableValue("north", new TriangleMembershipFunction(0, 90, 180)));
            angulo.addValue(new VariableValue("west", new TriangleMembershipFunction(90, 180, 270)));
            angulo.addValue(new VariableValue("south", new TriangleMembershipFunction(180, 270, 360)));
            angulo.addValue(new VariableValue("east", new InverseTrapezoidalMembershipFunction(0, 90, 270, 360)));


            system.addRule(new TagakiSugenoFuzzyRule(15, new string[] { "north", "left" }));
            system.addRule(new TagakiSugenoFuzzyRule(0, new string[] { "north", "center" }));
            system.addRule(new TagakiSugenoFuzzyRule(-15, new string[] { "north", "right" }));

            system.addRule(new TagakiSugenoFuzzyRule(15, new string[] { "west", "left" }));
            system.addRule(new TagakiSugenoFuzzyRule(15, new string[] { "west", "center" }));
            system.addRule(new TagakiSugenoFuzzyRule(-15, new string[] { "west", "right" }));

            system.addRule(new TagakiSugenoFuzzyRule( 15, new string[] { "south", "left" }));
            system.addRule(new TagakiSugenoFuzzyRule(-35, new string[] { "south", "center" }));
            system.addRule(new TagakiSugenoFuzzyRule(-15, new string[] { "south", "right" }));

            system.addRule(new TagakiSugenoFuzzyRule( 15, new string[] { "east", "left" }));
            system.addRule(new TagakiSugenoFuzzyRule(-15, new string[] { "east", "center" }));
            system.addRule(new TagakiSugenoFuzzyRule(-15, new string[] { "east", "right" }));

            FuzzySet setDistancia = new FuzzySet(distancia, -10);
            FuzzySet setAngulo = new FuzzySet(angulo, 90);
            FuzzySet[] sets = { setAngulo, setDistancia };

            textBox1.Text = system.CrispOutput(sets).ToString();

            //posRobot = new PointF(15, 15);
            //angRobot = 0;//Math.PI / 2;

            posPelota = new PointF(40, 80);

            pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);

            Random r = new Random();
            int i = 0;
            for (i = 0; i < robots.Length; i++)
                robots[i] = new Player(pictureBox1.Width, pictureBox1.Height,r);

            drawStuff();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Enabled = !timer1.Enabled;
            if (timer1.Enabled)
                button1.Text = "Stop";
            else
                button1.Text = "Play";
        }

        //private double getATan()
        //{
        //    if ((posPelota.X - posRobot.X) >= 0)// || true)
        //        return Math.Atan((posPelota.Y - posRobot.Y) / (posPelota.X - posRobot.X));
        //    else
        //        return Math.PI + Math.Atan((posPelota.Y - posRobot.Y) / (posPelota.X - posRobot.X));
        //}

        //private double getRoboAngulo()
        //{
        //    double res = 180 * (Math.PI / 2 - angRobot + this.getATan()) / Math.PI;
        //    if (0 <= res && res <= 2 * 360)
        //        return res;
        //    else if (res < 0)
        //        return res + 360;
        //    else
        //        return res - 360;
        //}

        //private double getRoboDistancia()
        //{
        //    return Math.Sqrt(Math.Pow(posPelota.Y-posRobot.Y,2) +Math.Pow(posPelota.X-posRobot.X,2))*Math.Sin(angRobot - this.getATan());
        //}

        private void button2_Click(object sender, EventArgs e)
        {
            SeekPelota();
        }

        private void SeekPelota()
        {
            foreach (Player robot in robots)
            {
                FuzzySet setDistancia = new FuzzySet(distancia, robot.getDistancia(posPelota));
                FuzzySet setAngulo = new FuzzySet(angulo, robot.getAngulo(posPelota));
                FuzzySet[] sets = { setAngulo, setDistancia };

                robot.angRobot += Math.PI * system.CrispOutput(sets) / 180;
                robot.posRobot.X += (float)(5 * Math.Cos(robot.angRobot));
                robot.posRobot.Y += (float)(5 * Math.Sin(robot.angRobot));
            }

            drawStuff();
            foreach (Player robot in robots)
            {
                if (Math.Sqrt(Math.Pow(posPelota.Y - robot.posRobot.Y, 2) + Math.Pow(posPelota.X - robot.posRobot.X, 2)) < 5)
                {
                    Random r = new Random();
                    posPelota.X = r.Next(pictureBox1.Width);
                    posPelota.Y = r.Next(pictureBox1.Height);
                }
            }
        }

        private void drawStuff()
        {

            Graphics g = Graphics.FromImage(pictureBox1.Image);
            g.Clear(pictureBox1.BackColor);
            foreach (Player robot in robots)
            {
                g.FillEllipse(Brushes.Red, (int)robot.posRobot.X - 5, (int)robot.posRobot.Y - 5, 10, 10);
                g.DrawLine(Pens.Black, (int)robot.posRobot.X, (int)robot.posRobot.Y, (int)(robot.posRobot.X + 5 * Math.Cos(robot.angRobot)), (int)(robot.posRobot.Y + 5 * Math.Sin(robot.angRobot)));
            }
            g.FillEllipse(Brushes.Black, (int)posPelota.X -3, (int)posPelota.Y -3, 6, 6);

            pictureBox1.Invalidate();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            SeekPelota();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}
